//
//  NcitBleDevice.m
//  BleHrateDemo
//
//  Created by Yongfeng Li on 8/15/14.
//  Copyright (c) 2014 Yongfeng Li. All rights reserved.
//

#import "NcitBleDevice.h"

#define _KgcovLb 2.20462262

@implementation NcitBleDevice {
    BOOL _bIsSuptBLe;
    BOOL _bAutoConnect;
    BOOL _bRcvBLeData;
    BOOL _bConnBleDev;
    NSString* _sBleUuid;
    
    id _bleDelegate;
    
    CBCentralManager*   _bleMgr;
    CBPeripheral*       _pBleDevSvr;
    CBCharacteristic*   _pBleDevChar;
    NSMutableArray*     hrConntMonitors;
    
    NSArray* _arSelBleDev;
    NSTimer* _measTimer;
    
    BOOL _bWriteBraceletVal;
    NSDateFormatter* _dtFormat;
    
    BOOL _bBodyMale;
    short _nBodyYear;
    float _fBodyHgt;
    //NSString* _rcvData;
}


/*****************************/
/*    ble strap gague   */
/*****************************/

#pragma mark - BLE init
- (id) initBleDevice
{
    _bIsSuptBLe = NO;
    _bAutoConnect = YES;
    _bRcvBLeData = NO;
    _bConnBleDev = NO;
    //BLE ini
    hrConntMonitors = [[NSMutableArray alloc] init];
    _bleMgr = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
    
    _pBleDevSvr = nil;
    _pBleDevChar = nil;
    _arSelBleDev = nil;
    _measTimer = nil;
    
    _dtFormat = [[NSDateFormatter alloc] init];
    //_rcvData = [NSString alloc].init;
    
    _bWriteBraceletVal = NO;
    
    _bBodyMale = NO;
    _nBodyYear = -1;
    _fBodyHgt = 0.0;
    
    return self;
}


#pragma mark - BLE center delegate methods
- (BOOL) isLECapableHardware
{
    NSString * state = nil;
    switch ([_bleMgr state])
    {
        case CBCentralManagerStateUnsupported:
            state = @"The platform/hardware doesn't support Bluetooth Low Energy.";
            break;
        case CBCentralManagerStateUnauthorized:
            state = @"The app is not authorized to use Bluetooth Low Energy.";
            break;
        case CBCentralManagerStatePoweredOff:
            state = @"Bluetooth is currently powered off.";
            break;
        case CBCentralManagerStatePoweredOn:
            return TRUE;
        case CBCentralManagerStateUnknown:
        default:
            return FALSE;
            
    }
    
    NSLog(@"Central manager state: %@", state);
    
    /*[self cancelScanSheet:nil];
     NSAlert *alert = [[[NSAlert alloc] init] autorelease];
     [alert setMessageText:state];
     [alert addButtonWithTitle:@"OK"];
     [alert setIcon:[[[NSImage alloc] initWithContentsOfFile:@"AppIcon"] autorelease]];
     [alert beginSheetModalForWindow:[self window] modalDelegate:self didEndSelector:nil contextInfo:nil];*/
    return FALSE;
}

//bluetooth start
- (void) startMeas:(NSString*)sBleUUID
{
    _sBleUuid = sBleUUID;
    
    if(!_bIsSuptBLe) {
        if (_bleDelegate && [_bleDelegate respondsToSelector:@selector(bleDiscoverFailed)]) {
            [_bleDelegate bleDiscoverFailed];
        }
        return;
    }
    [self stopMeas];
    
    NSUInteger nCount = hrConntMonitors.count;
    if(nCount > 0)
        [hrConntMonitors removeAllObjects];
    
    _measTimer = [NSTimer scheduledTimerWithTimeInterval:6.00 target:self selector:@selector(onMeasTimer) userInfo:nil repeats:NO];
    NSDictionary *options = @{ CBCentralManagerScanOptionAllowDuplicatesKey: ((_sBleUuid == nil)? @YES: @NO) };
    //[_bleMgr scanForPeripheralsWithServices:nil options:options];
    if(sBleUUID == nil)
        [_bleMgr scanForPeripheralsWithServices:nil options:options];
    else
        [_bleMgr scanForPeripheralsWithServices:[NSArray arrayWithObject:[CBUUID UUIDWithString:sBleUUID]] options:options];
}

- (void) stopMeas
{
    if(_measTimer != nil) {
        [_measTimer invalidate];
        _measTimer = nil;
    }
    
    if(_pBleDevSvr != nil) {
        [_bleMgr cancelPeripheralConnection:_pBleDevSvr];
        _pBleDevSvr = nil;
        _bConnBleDev = NO;
    }
}

- (void) stopScan
{
    if(!_bIsSuptBLe)
        return;
    /*if(_measTimer != nil) {
        [_measTimer invalidate];
        _measTimer = nil;
    }*/
    [_bleMgr stopScan];
    
    //[self _stopProgressView];
}

- (void) centralManagerDidUpdateState:(CBCentralManager *)central
{
    _bIsSuptBLe = [self isLECapableHardware];
    
    /*if(!_bIsSuptBLe) {
        if (_bleDelegate && [_bleDelegate respondsToSelector:@selector(bleDiscoverFailed)]) {
            [_bleDelegate bleDiscoverFailed];
        }
    }*/
    
    if (_bleDelegate && [_bleDelegate respondsToSelector:@selector(bleSupport:)]) {
        [_bleDelegate bleSupport:_bIsSuptBLe];
    }
    //_btnStart.enabled = _bIsSuptBLe;
}

/*
 Invoked when the central discovers blood pressure gague peripheral while scanning.
 */
- (void) centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)aPeripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
    if(aPeripheral == nil)
        return;
    
    BOOL bExists = [hrConntMonitors containsObject:aPeripheral];
    if(!bExists) {
        if(_bAutoConnect) {
            //aPeripheral.UUID
            NSString* sName = aPeripheral.name;
            if(sName == nil)
                return;
            
            BOOL bBpDev = [sName isEqual:@"Dual-SPP"] || [sName isEqualToString:@"Bluetooth BP"] || [sName isEqualToString:@"Electronic Scale"]
            ||[sName isEqualToString:@"HjT"] || [sName isEqualToString:@"HNY200KD"] || [sName isEqualToString:@"BOLUTEK"];
            BOOL bBracelet = [sName isEqualToString:@"HW382A"] || [sName isEqualToString:@"HW652"];
            BOOL bYunMai = [sName isEqualToString:@"YUNMAI-JY0002"];
            //BOOL bBpDev = [aPeripheral.identifier isEqual:[CBUUID UUIDWithString:@"FFF1"]] || [aPeripheral.identifier isEqual:[CBUUID UUIDWithString:@"2A51"]];
            if(_sBleUuid != nil || bBpDev || bBracelet || bYunMai) {
                _pBleDevSvr = aPeripheral;
                [_bleMgr connectPeripheral:_pBleDevSvr options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES]
                                                            forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey]];
                //if(bBpDev)
                    [self stopScan];
            }
            if(bBracelet)
                _bWriteBraceletVal = NO;
        }
        [hrConntMonitors addObject:aPeripheral];
    }
    
    if(hrConntMonitors.count > 0) {
        //if(_peripheral == nil || (!_bLoadStoreDevice && [self isLECapableHardware])) {
        if(_pBleDevSvr.state != CBPeripheralStateConnected) { //&& !_bLoadStoreDevice
            //[self loadScanSaverDevices:aPeripheral.identifier.UUIDString];
            if(_bleDelegate && [_bleDelegate respondsToSelector:@selector(bleMgrDiscover:)]) {
                [_bleDelegate bleMgrDiscover:aPeripheral];
            }
        }
    }
}

/*
 Invoked when the central manager retrieves the list of known peripherals.
 Automatically connect to first known peripheral
 */
- (void)centralManager:(CBCentralManager *)central didRetrievePeripherals:(NSArray *)peripherals
{
    //if(_bLoadStoreDevice)
    //return;
    NSLog(@"Retrieved peripheral: %u - %@", (int)[peripherals count], peripherals);
    NSUInteger nCount = hrConntMonitors.count;
    if(nCount > 1 && _arSelBleDev == nil) {
        if(!_bAutoConnect)
            [self stopScan];
        if(_pBleDevSvr) {
            [_bleMgr cancelPeripheralConnection:_pBleDevSvr];
            //_peripheral = nil;
        }
        return;
    }
    /* If there are any known devices, automatically connect to it.*/
    if([peripherals count] > 0/* && autoConnect*/) {
        _pBleDevSvr = [peripherals objectAtIndex:0];
        //[_pBleHrateSvr retain];
        [_bleMgr connectPeripheral:_pBleDevSvr options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES]
                                                        forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey]];
        //_bLoadStoreDevice = YES;
    }
}

/*
 Invoked whenever a connection is succesfully created with the peripheral.
 Discover available services on the peripheral
 */
- (void) centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)aPeripheral
{
    [aPeripheral setDelegate:self];
    [aPeripheral discoverServices:nil];
    _pBleDevSvr = aPeripheral;
    
    if (![hrConntMonitors containsObject:aPeripheral])
		[hrConntMonitors addObject:aPeripheral];
    
    if(_bleDelegate  && [_bleDelegate respondsToSelector:@selector(bleDevConnected)]) {
        [_bleDelegate bleDevConnected];
    }
    
    
    [self stopScan];
    _bRcvBLeData = NO;
    _bConnBleDev = YES;
}

/*
 Invoked whenever an existing connection with the peripheral is torn down.
 Reset local variables
 */
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)aPeripheral error:(NSError *)error
{
    CBPeripheral* service = nil;
    for (service in hrConntMonitors) {
        if (service == aPeripheral) {
            [hrConntMonitors removeObject:service];
            //[peripheralDelegate alarmServiceDidChangeStatus:service];
            break;
        }
    }
    if(_pBleDevSvr != nil) {
        [_bleMgr cancelPeripheralConnection:_pBleDevSvr];
        _pBleDevSvr = nil;
    }
    [self stopMeas];
    //[self startScan];
    
    if(_bleDelegate  && [_bleDelegate respondsToSelector:@selector(bleDisconnected)]) {
        [_bleDelegate bleDisconnected];
    }
}

/*
 Invoked whenever the central manager fails to create a connection with the peripheral.
 */
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)aPeripheral error:(NSError *)error
{
    NSLog(@"Fail to connect to peripheral: %@ with error = %@", aPeripheral, [error localizedDescription]);
    //[connectButton setTitle:@"Connect"];
    if( _pBleDevSvr != nil && _pBleDevSvr == aPeripheral)
    {
        [_pBleDevSvr setDelegate:nil];
        //[_pBleHrateSvr release];
        _pBleDevSvr = nil;
    }
    //_lblState.text = [NSString stringWithFormat: @"%@ %s", [aPeripheral name], "Fail to connect"];
}

- (void) centralManager:(CBCentralManager *)central didFailToRetrievePeripheralForUUID:(CFUUIDRef)UUID error:(NSError *)error
{
	/* Nuke from plist. */
	//[self removeSavedDevice:UUID];
}

#pragma mark - CBPeripheral delegate methods
/*
 Invoked upon completion of a -[discoverServices:] request.
 Discover available characteristics on interested services
 */
- (void) peripheral:(CBPeripheral *)aPeripheral didDiscoverServices:(NSError *)error
{
    for (CBService *aService in aPeripheral.services)
    {
        //NSLog(@"Service found with UUID: %@", aService.UUID);
        //lblMsg.text = [NSString stringWithFormat:@"%@", aService.UUID];
        NSString* sBLeName = aService.peripheral.name;
        NSString* sUuidStr = aService.UUID.UUIDString;
        
       
        if ([sBLeName isEqualToString:@"HjT"] || [sBLeName isEqualToString:@"HNY200KD"] || [sBLeName isEqualToString:@"BOLUTEK"] || [aService.UUID isEqual:[CBUUID UUIDWithString:@"FFE0"]]) {
                
            if([sBLeName isEqualToString:@"YUNMAI-JY0002"]) { // new Accuro Ble svale
                //[aPeripheral discoverCharacteristics:nil forService:aService];
                [aPeripheral discoverCharacteristics:@[[CBUUID UUIDWithString:@"FFE4"],[CBUUID UUIDWithString:@"FFE5"]] forService:aService];
            }
            else {
                [aPeripheral discoverCharacteristics:nil forService:aService];
            }
        }
        else if([sUuidStr isEqualToString:@"FFE5"]) {
            [aPeripheral discoverCharacteristics:@[[CBUUID UUIDWithString:@"FFE9"]] forService:aService];
        }
    }
}

/*
 Invoked upon completion of a -[discoverCharacteristics:forService:] request.
 Perform appropriate operations on interested characteristics
 */
- (void) peripheral:(CBPeripheral *)aPeripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
    //write to peripheral
    //NSString* sUuidStr = service.UUID.UUIDString;
    //BOOL bBldDevFound = NO;
    
    for (CBCharacteristic *characteristic in service.characteristics) {
        NSLog(@"Discovered characteristic %@", characteristic);
    }
    
    if ([service.UUID isEqual:[CBUUID UUIDWithString:@"FFE0"]]) {
        for (CBCharacteristic *aChar in service.characteristics) {
            if([aChar.UUID isEqual:[CBUUID UUIDWithString:@"FFE4"]]) { //yunmai accuro scale read
                [_pBleDevSvr setNotifyValue:YES forCharacteristic:aChar];
                //[aPeripheral discoverCharacteristics:@[[CBUUID UUIDWithString:@"FFE5"]] forService:service];
            }
            else if([aChar.UUID isEqual:[CBUUID UUIDWithString:@"FFE9"]]) { //yunmai accuro scale write
                _pBleDevSvr = aPeripheral;
                [_pBleDevSvr setNotifyValue:YES forCharacteristic:aChar];
                if(_bleDelegate && [_bleDelegate respondsToSelector:@selector(sendDataToYunmaiBLeDev:)])
                    [_bleDelegate sendDataToYunmaiBLeDev:aChar];
            }
        }
    }
    else  if ([service.UUID isEqual:[CBUUID UUIDWithString:@"FFE5"]]) { //yumai oth service
         _pBleDevSvr = aPeripheral;
        aPeripheral.delegate = self;
        for (CBCharacteristic *aChar in service.characteristics) {
            if([aChar.UUID isEqual:[CBUUID UUIDWithString:@"FFE9"]]) { //yunmai accuro scale write
                [_pBleDevSvr setNotifyValue:YES forCharacteristic:aChar];
                if(_bleDelegate && [_bleDelegate respondsToSelector:@selector(sendDataToYunmaiBLeDev:)])
                    [_bleDelegate sendDataToYunmaiBLeDev:aChar];
            }
        }
    }
    
}


/*
 Invoked upon completion of a -[readValueForCharacteristic:] request or on the reception of a notification/indication.
 */
- (double) getYunmaiBleWgtData:(const uint8_t *)rcvData len:(NSUInteger)nDataLen chara:(CBCharacteristic *)characteristic
{
    int nIdx = 6;
    float fWgtKg = 0;
    float fWgtVal = 0.0;
    short nUn = 2;
    if(nDataLen == 0x11) {
        nIdx = 11;
        uint8_t val[2] = {0x02, 0x94};
        NSData* valData = [NSData dataWithBytes:(void*)&val length:sizeof(val)];
        [_pBleDevSvr writeValue:valData forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];
        
        //uint8_t nLen = rcvData[0];
        //uint8_t nCmdNo = rcvData[1];
        
        uint8_t hWgt = rcvData[nIdx];
        uint8_t lWgt = rcvData[nIdx + 1];
        short nWgt = (hWgt << 8) + lWgt;
        fWgtKg = nWgt / 100.0;
        fWgtVal = fWgtKg * _KgcovLb;//2.20462262;
        
        
        /*uint8_t hRes = rcvData[13];
         uint8_t lRes = rcvData[14];
         float fRes = ((hRes << 8) + lRes);*/
        
        uint8_t hFat = rcvData[15];
        uint8_t lFat = rcvData[16];
        float fFat = ((hFat << 8) + lFat) / 100.0;
        
        //aater
        float fWat = (100.0 -  fFat)  * 11.0 / 16.0; //0.73;
        //musele & bone
        float fMus = (fWat * 61 + 1600 + 2 * fWgtKg - _fBodyHgt) / 100.0 - (_bBodyMale? 4: 0);
        float fBone = (float)(fFat * 103.0 + fWat *  312.0 + fWgtKg * 237.0 + _fBodyHgt * 237.0 - 154170.0 - 49.0 * _nBodyYear - 246.0 * fMus) / 10000.0f + 13.0f;
        fBone = fabsf(fBone) * _KgcovLb;;
        if(fFat == 0.0) {
            fWat = 0.0f;
            fMus = 0.0f;
            fBone = 0.0f;
        }
        
        [_bleDelegate recvedBleWgtData:fWgtVal fat:fFat wat:fWat mus:fMus bone:fBone wUnit:nUn fatwatInc:YES hgt:_fBodyHgt];
    }
    return fWgtKg;
   
}

-(NSString *)getUTCFormateDate:(NSDate *)localDate
{
    //NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
    NSTimeZone *timeZone = [NSTimeZone localTimeZone];
    [_dtFormat setTimeZone:timeZone];
    [_dtFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    //[_dtFormat setDateFormat:@"MM"];
    //int month = [[_dtFormat stringFromDate:[NSDate date]] intValue];
    NSString *dateString = [_dtFormat stringFromDate:localDate];
    //[_dtFormat release];
    return dateString;
}

- (void) recvBraceLetData:(const uint8_t *)rcvData len:(NSUInteger)nDataLen char:(CBCharacteristic*)bleChar
{
    /*if(nDataLen == 6) {
        NSString* sData = [NSString stringWithFormat:@"UTC Length: %li-> %@", (long)nDataLen, characteristic.value.description];
        [_bleDelegate recvedBleOthData:sData];
    }*/
    
    uint8_t _nBraceletIdx = (rcvData[0] & 0xf0) >> 4;
    uint8_t _nBraceletCmd = rcvData[0] & 0x0f;
    if(! _bWriteBraceletVal && nDataLen == 17 && _nBraceletCmd == 0x01) {

        float fWgt = ((rcvData[7] << 8) + rcvData[8]) / 10.0;
        Byte nAge = rcvData[9];
        Byte nHgt = rcvData[10];
        Byte nSex = rcvData[12];
        [_bleDelegate recvedBleOthData:[NSString stringWithFormat:@"wgt:%.1f kg, Age:%i, Hgt:%i cm Sex: %@", fWgt, nAge, nHgt, ((nSex==0)?@"Female":@"Male")]];
        
        [NSThread sleepForTimeInterval:0.5];
        if(_pBleDevSvr != nil && _pBleDevChar != nil) {
            uint8_t val[4] = {0xE0, 0x00, 0x00, 0xE0};
            val[1] = _nBraceletIdx;
            val[3] += _nBraceletIdx;
            NSData* valData = [NSData dataWithBytes:(void*)&val length:sizeof(val)];
            [_pBleDevSvr writeValue:valData forCharacteristic:_pBleDevChar type:CBCharacteristicWriteWithResponse];
            //[_pBleDevSvr writeValue:valData forCharacteristic:bleChar type:CBCharacteristicWriteWithoutResponse];
            
            _bWriteBraceletVal = YES;
        }
        
    }
    else if(nDataLen == 6) {
        NSString* sData = [NSString stringWithFormat:@"%li bytes: %02X %02X %02X %02X %02X %02X", (long)nDataLen, rcvData[0], rcvData[1], rcvData[2], rcvData[3], rcvData[4], rcvData[5]];
        [_bleDelegate recvedBleOthData:sData];
        if(_nBraceletCmd == 0x0 ) {
            uint8_t val[4] = {0xE0, 0x00, 0x01, 0xE1};
            //val[1] = _nBraceletIdx;
            //val[3] += _nBraceletIdx;
            NSData* valData = [NSData dataWithBytes:(void*)&val length:sizeof(val)];
            [self sendDataToBLeDev:_pBleDevChar data:valData type:CBCharacteristicWriteWithResponse];
        }
        
    }
    else if(nDataLen == 15) { //fitness info
        int nSteps = (rcvData[5] >> 16) + (rcvData[6] >> 8) + rcvData[7];
        int nDists = (rcvData[8] >> 16) + (rcvData[9] >> 8) + rcvData[10];
        int nCalor =  (rcvData[11] >> 16) + (rcvData[12] >> 8) + rcvData[13];
        NSString* sInfo = [NSString stringWithFormat:@"steps:%i, Dists:%i, Calo:%i", nSteps, nDists, nCalor];
        [_bleDelegate recvedBleOthData:sInfo];
        
        uint8_t val[4] = {0xE0, 0x02, 0x00, 0xE2};
        //val[1] = _nBraceletIdx;
        //val[3] += _nBraceletIdx;
        NSData* valData = [NSData dataWithBytes:(void*)&val length:sizeof(val)];
        [self sendDataToBLeDev:_pBleDevChar data:valData type:CBCharacteristicWriteWithResponse];
        
    }
    else if(nDataLen == 20) {
        NSString* sInfo = @"data package leng 20, beging details";
        [_bleDelegate recvedBleOthData:sInfo];
        
    }
    else if(nDataLen == 4) {
        Byte nIdx = (rcvData[0] & 0xf0) >> 4;
        Byte nCom = rcvData[0] & 0x0f;
        BOOL bEnd = rcvData[1] == 0x03;
        Byte nPackLen = rcvData[2];
        
        NSString* sEnd = @"";
        NSString* sInfo = [NSString stringWithFormat:@"Recv package(4): idx:%i, com:%i", nIdx, nCom];
        if(bEnd) {
            sEnd = [NSString stringWithFormat:@". End len: %i", nPackLen];
        }
        
        NSMutableString* sInfos = [NSMutableString stringWithFormat:sInfo, sEnd];
        [_bleDelegate recvedBleOthData:sInfos];
        
    }
    else {
        //NSString* sInfo = [NSString stringWithFormat: @"other data received: %ld", (long)nDataLen];
        //[_bleDelegate recvedBleOthData:sInfo];
        
        NSString* sData = [NSString stringWithFormat:@"UTC Length: %li-> %@", (long)nDataLen, bleChar.value.description];
        [_bleDelegate recvedBleOthData:sData];
    }
}

- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    
    if (error) {
        NSLog(@"Error changing notification state: %@", error.localizedDescription);
    }
    
    // Notification has started
    if (characteristic.isNotifying) {
        NSLog(@"Notification began on %@", characteristic);
    }
}

- (void) peripheral:(CBPeripheral *)aPeripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
    //NSLog(@"UUID: %@", characteristic.UUID);
    NSString* sBLeName = @"";
    for (CBService *aService in aPeripheral.services) {
        sBLeName = aService.peripheral.name;
    }
    
    BOOL bBracelet = [characteristic.UUID isEqual:[CBUUID UUIDWithString:@"FC20"]];
    if(!bBracelet)
        bBracelet = [characteristic.UUID isEqual:[CBUUID UUIDWithString:@"FC00"]];
    BOOL bYunMai = [characteristic.UUID isEqual:[CBUUID UUIDWithString:@"FFE4"]] && [sBLeName isEqualToString:@"YUNMAI-JY0002"];

    
    NSUInteger nDataLen = characteristic.value.length;
    const uint8_t* rcvData = [characteristic.value bytes];
    
    if(bYunMai) {
        [self getYunmaiBleWgtData:rcvData len:nDataLen chara:characteristic];
    }
    else if(bBracelet) {
        if( (characteristic.value)  || !error ) {
            // Update UI with heart rate data
            //if(_bRcvBLeData)
                //return;
            
            if (_bleDelegate && [_bleDelegate respondsToSelector:@selector(recvedBleOthData:)]) {
                //NSString* sData = [_rcvData initWithData:characteristic.value encoding:NSASCIIStringEncoding];
                //[_bleDelegate recvedBleOthData:sData];
                //[_bleDelegate recvedBleOthData:characteristic.value.description];
                [self recvBraceLetData: rcvData len: nDataLen char: characteristic];
                //[_pBleDevSvr setNotifyValue:YES forCharacteristic:characteristic];
            }
        }
    
    }
}

- (void) onMeasTimer
{
    if(_measTimer != nil) {
        [_measTimer invalidate];
        _measTimer = nil;
    }
    //rem for test and debug
    if(_pBleDevSvr == nil) {
        if (_bleDelegate && [_bleDelegate respondsToSelector:@selector(onBLeDevDiscoverTimeOut)]) {
            [_bleDelegate onBLeDevDiscoverTimeOut];
        }
    }
}

- (void) sendDataToBLeDev:(CBCharacteristic*)aChar data:(NSData*)valData type:(CBCharacteristicWriteType)hdType;
{
    const uint8_t*  dBody = valData.bytes;
    _bBodyMale = dBody[8] == 1;
    _nBodyYear = (short)dBody[9];
    _fBodyHgt = (float)dBody[7];
    [_pBleDevSvr writeValue:valData forCharacteristic:aChar type:hdType];
}

- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
    NSString* sError = error.description;
    if (_bleDelegate && [_bleDelegate respondsToSelector:@selector(recvedBleOthData:)]) {
        [_bleDelegate recvedBleOthData:sError];
    }
}

#pragma mark /*-- BLE dev matcch --*/
- (NSUInteger) connBLEDevCount
{
    return hrConntMonitors.count;
}

- (CBPeripheral*) listBleDev:(NSInteger)nIdx
{
    if(nIdx > hrConntMonitors.count-1)
        return nil;
    return [hrConntMonitors objectAtIndex:nIdx];
}

- (void) retrievePeripherals:(NSArray *)peripheralUUID
{
    [_bleMgr retrievePeripherals:peripheralUUID];
    //return [_bleMgr retrievePeripheralsWithIdentifiers: peripheralUUID];
    
    /*NSUUID *uuid = [[NSUUID alloc]initWithUUIDString:peripheralUUID];
     //where savedUUID is the string version of the NSUUID you've saved somewhere
     
     NSArray *peripherals = [_bleMgr retrievePeripheralsWithIdentifiers:@[uuid]];
     return peripherals;*/
}

- (void) cancelPeripheralConnection/*:(CBPeripheral *)peripheral*/
{
    [_bleMgr cancelPeripheralConnection:_pBleDevSvr];
    _pBleDevSvr = nil;
}

@end
